ひとりNavigation API Advent Calendar 19日目
https://gyazo.com/8231fffebf08cecf8c8eb1aa137892d7
<ClientRouter />を呼び出すことでSPAのような挙動になる 当初は<ViewTransitions />を呼び出す形だったのが<ClientRouter />に差し変わった
クリックイベントのインターセプト処理
仕組み
クライアントサイドナビゲーションのプロセス
1. サイト訪問者が以下のいずれかの操作でナビゲーションを開始
サイト内の別ページへリンクする <a> タグをクリック
ブラウザの「戻る」ボタンをクリック
ブラウザの「進む」ボタンをクリック
2. ルーターが次のページの取得を開始
3. ルーターは <html> 要素に data-astro-transition 属性を追加し、値を "forward" または "back" に設定
4. ルーターは document.startViewTransition を呼び出す
ブラウザは現在のページ状態をスクリーンショットする
5. startViewTransition のコールバック内で、ルーターは swap(入れ替え) を実行する
<head> の内容を入れ替え。
ただし以下は保持される
新しいページにも存在するスタイルシート DOM ノード(FOUC防止のため) 新しいページにも存在するスクリプト
transition:persist が付与され、新しいページにも対応要素がある <head> 要素
<body> を新しいページの <body> に完全に置き換え
transition:persist が付与された要素は、新しいページに存在する場合、新しい DOM に移動
必要に応じてスクロール位置を復元する
astro:after-swap イベントを document に発火(swap処理の終了)
6. ルーターは新しいスタイルシートの読み込みを待機し、TransitionをResolveする
7. ルーターは新しいページに追加されたスクリプトを実行
8. astro:page-load イベントが発火
これでナビゲーションプロセスの終了
code:js
export async function navigate(href: string, options?: Options) {
if (inBrowser === false) {
if (!navigateOnServerWarned) {
// instantiate an error for the stacktrace to show to user.
const warning = new Error(
'The view transitions client API was called during a server side render. This may be unintentional as the navigate() function is expected to be called in response to user interactions. Please make sure that your usage is correct.',
);
warning.name = 'Warning';
console.warn(warning);
navigateOnServerWarned = true;
}
return;
}
await transition('forward', originalLocation, new URL(href, location.href), options ?? {});
}
コンテンツのフェッチ
doSwap()イベントが発火され、swap()関数によって現在のページのDOM(head要素とbody要素)が新しいページのDOMに置き換えられる スクリプトの実行状態のマーク
ルート要素(<html>)の属性の更新
<head>の更新
<body>の置き換え
document.activeElementされるものを探してフォーカスさせる処理
code:js
const announce = () => {
let div = document.createElement('div');
div.setAttribute('aria-live', 'assertive');
div.setAttribute('aria-atomic', 'true');
div.className = 'astro-route-announcer';
document.body.append(div);
setTimeout(
() => {
let title = document.title || document.querySelector('h1')?.textContent || location.pathname;
div.textContent = title;
},
// Much thought went into this magic number; the gist is that screen readers
// need to see that the element changed and might not do so if it happens
// too quickly.
60,
);
};
60の根拠があいまいなのがね…yamanoku.icon
code:js
currentTransition.viewTransition?.updateCallbackDone.finally(async () => {
await runScripts();
onPageLoad();
announce();
});